/*******************************************************************************
**                                                                            **
** Copyright (C)    (2016)                                               **
**                                                                            **
** All rights reserved.                                                       **
**                                                                            **
** This document contains proprietary information belonging to .         **
** Passing on and copying of this document, and communication                 **
** of its contents is not permitted without prior written authorization.      **
**                                                                            **
********************************************************************************
**                                                                            **
**  FILENAME    : Xcp_Pgm.c                                                   **
**                                                                            **
**  Created on  :                                                             **
**  Author      : qinchun.yang                                                **
**  Vendor      :                                                             **
**  DESCRIPTION : Implementation of the XCP_Pgm command			              **
**                                                                            **
**  SPECIFICATION(S) :   AUTOSAR classic Platform 4.2.2                       **
**                                                                            **
*******************************************************************************/
/*=======[V E R S I O N  I N F O R M A T I O N]===============================*/

#define XCP_PGM_C_AR_MAJOR_VERSION  4u
#define XCP_PGM_C_AR_MINOR_VERSION  2u
#define XCP_PGM_C_AR_PATCH_VERSION  2u
#define XCP_PGM_C_SW_MAJOR_VERSION  1u
#define XCP_PGM_C_SW_MINOR_VERSION  0u
#define XCP_PGM_C_SW_PATCH_VERSION  0u

/*=======[I N C L U D E S]====================================================*/
#include "Xcp_Internal.h"
/*=======[V E R S I O N  C H E C K]===========================================*/

#if (XCP_PGM_C_AR_MAJOR_VERSION != XCP_H_AR_MAJOR_VERSION)
  #error "Xcp_Pgm.c : Mismatch in Specification Major Version"
#endif
#if (XCP_PGM_C_AR_MINOR_VERSION != XCP_H_AR_MINOR_VERSION)
  #error "Xcp_Pgm.c : Mismatch in Specification Major Version"
#endif
#if (XCP_PGM_C_AR_PATCH_VERSION != XCP_H_AR_PATCH_VERSION)
  #error "Xcp_Pgm.c : Mismatch in Specification Major Version"
#endif
#if (XCP_PGM_C_SW_MAJOR_VERSION != XCP_H_SW_MAJOR_VERSION)
  #error "Xcp_Pgm.c : Mismatch in Specification Major Version"
#endif
#if (XCP_PGM_C_SW_MINOR_VERSION != XCP_H_SW_MINOR_VERSION)
  #error "Xcp_Pgm.c : Mismatch in Specification Major Version"
#endif
#if (XCP_PGM_C_SW_PATCH_VERSION != XCP_H_SW_PATCH_VERSION)
  #error "Xcp_Pgm.c : Mismatch in Specification Major Version"
#endif



#if (XCP_PL_PGM == (XCP_PL_PGM & XCP_RESOURCE))
/*=======[M A C R O S]========================================================*/

/* SIZE Limitation */
#define XCP_PROGRAMMAX_SIZE         ((XCP_MAX_CTO_PGM/XCP_AG) - 0x01u)

/* Xcp Access Mode Type */
#define XCP_ABSOLUTE_ACCESS         0x00u
#define XCP_FUNCTIONAL_ACCESS       0x01u

/* Limitation of flash driver */
#define XCP_FLS_MIN_WRITE_SIZE      256u
#define XCP_FLS_DATA_BUFFER_SIZE    (XCP_FLS_MIN_WRITE_SIZE+6)

/* Flash area selection */
#define XCP_FLASHAREA_CAL           0x01u
#define XCP_FLASHAREA_CODE          0x02u
#define XCP_FLASHAREA_NVRAM         0x04u

/* parameters of GET_PGM_PROCESSOR_INFO */
#define COMPRESSION_SUPPORTED       0x02u
#define COMPRESSION_REQUIRED        0x03u
#define ENCRYPTION_SUPPORTED        0x04u
#define ENCRYPTION_REQUIRED         0x05u
#define NON_SEQ_PGM_SUPPORTED       0x06u
#define NON_SEQ_PGM_REQUIRED        0x07u

#define PGM_PROPERTIES              ((1u << XCP_ABSOLUTE_ACCESS)|(1u << XCP_FUNCTIONAL_ACCESS))

/* Bitmasks for pending task */
#define XCP_CLEAR_TASK              0x01u
#define XCP_CLEAR_PENDING           0x02u
#define XCP_PROGRAM_TASK            0x04u
#define XCP_PROGRAM_PENDING         0x08u
#define XCP_BLOCK_PROGRAM_TASK      0x10u
#define XCP_BLOCK_PROGRAM_PENDING   0x20u

/* mode for get sector info */
#define XCP_GER_SECTOR_INFO_MOD_STAD	0u
#define XCP_GER_SECTOR_INFO_MOD_LEN     1u
#define XCP_GER_SECTOR_INFO_MOD_NAME    2u

/*Address Position & Size check wheather in ROM RP*/
#define CHECK_XCP_FLASH_ROM_MEM(addr, size, sectorNum) (((addr) >= Xcp_SectorInfo[sectorNum].progStartAddr) \
                        && (((addr) + (size)) <= ( Xcp_SectorInfo[sectorNum].progStartAddr +  Xcp_SectorInfo[sectorNum].progDataSize)))


/*=======[T Y P E   D E F I N I T I O N S]====================================*/
typedef enum
{
    SEQ_OK = 0,
    SEQ_ERROR,
    SEQ_OUTRANGE,
    SEQ_DENIED
}Xcp_SeqCheckType;

typedef VAR(uint16,TYPEDEF) Xcp_PgmBufferIndexType;

/*=======[E X T E R N A L   D A T A]==========================================*/
#define XCP_START_SEC_VAR_INIT_UNSPECIFIED
#include "XCP_MemMap.h"
VAR(Xcp_PgmStautsType, XCP_VAR) Xcp_PgmStauts = XCP_PGM_IDLE;
#define XCP_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "XCP_MemMap.h"
/*=======[E X T E R N A L   F U N C T I O N   D E C L A R A T I O N S]========*/

/*=======[I N T E R N A L   D A T A]==========================================*/


#define XCP_START_SEC_VAR_CLEARED_8
#include "XCP_MemMap.h"
static VAR(uint8, XCP_VAR) Xcp_pgmPendingFlag;
#define XCP_STOP_SEC_VAR_CLEARED_8
#include "XCP_MemMap.h"

#define XCP_START_SEC_VAR_CLEARED_8
#include "XCP_MemMap.h"
static VAR(uint8, XCP_VAR) Xcp_flsBuffer[XCP_FLS_DATA_BUFFER_SIZE];
#define XCP_STOP_SEC_VAR_CLEARED_8
#include "XCP_MemMap.h"

#define XCP_START_SEC_VAR_CLEARED_UNSPECIFIED
#include "XCP_MemMap.h"
static VAR(Xcp_PgmBufferIndexType, XCP_VAR) Xcp_flsBufferSize;
#define XCP_STOP_SEC_VAR_CLEARED_UNSPECIFIED
#include "XCP_MemMap.h"

#define XCP_START_SEC_VAR_CLEARED_32
#include "XCP_MemMap.h"
static VAR(uint32, XCP_VAR) Xcp_flsTargetAddr;
#define XCP_STOP_SEC_VAR_CLEARED_32
#include "XCP_MemMap.h"

/* Clear and Program Access Mode(Absolute or Functional)
 * They may be different access mode.
 */
#define XCP_START_SEC_VAR_INIT_8
#include "XCP_MemMap.h"
static VAR(uint8, XCP_VAR) Xcp_Clear_AccessMode = XCP_ABSOLUTE_ACCESS;
static VAR(uint8, XCP_VAR) Xcp_Program_AccessMode = XCP_ABSOLUTE_ACCESS;
#define XCP_STOP_SEC_VAR_INIT_8
#include "XCP_MemMap.h"

/* indicate Xcp program_clear range and
 * also used in Program command when use functional access mode
 */
#define XCP_START_SEC_VAR_CLEARED_32
#include "XCP_MemMap.h"
static VAR(uint32, XCP_VAR) XCP_flashAreaSelect;
#define XCP_STOP_SEC_VAR_CLEARED_32
#include "XCP_MemMap.h"

#define XCP_START_SEC_VAR_INIT_32
#include "XCP_MemMap.h"
/* clear start address for program_clear command and pending task */
static VAR(uint32, XCP_VAR) Xcp_clearStartAddr = 0xa0240000u;
#define XCP_STOP_SEC_VAR_INIT_32
#include "XCP_MemMap.h"

#define XCP_START_SEC_VAR_CLEARED_32
#include "XCP_MemMap.h"
/* clear size for program_clear command and pending task */
static VAR(uint32, XCP_VAR) Xcp_clearSize;
#define XCP_STOP_SEC_VAR_CLEARED_32
#include "XCP_MemMap.h"

#if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
#define XCP_START_SEC_VAR_INIT_BOOLEAN
#include "XCP_MemMap.h"
/*Indicate which sector be selected for PROGRAM_CLEAR*/
static VAR(boolean, XCP_VAR) Xcp_sectorCleared[XCP_MAX_SECTOR] = {FALSE};
/*Indicate which sector be selected for PROGRAM*/
static VAR(boolean, XCP_VAR) Xcp_sectorProgramed[XCP_MAX_SECTOR] = {FALSE};
#define XCP_STOP_SEC_VAR_INIT_BOOLEAN
#include "XCP_MemMap.h"
#endif /* XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON */

#define XCP_START_SEC_VAR_INIT_8
#include "XCP_MemMap.h"
/* block sequence counter used for program in functional access mode */
static VAR(uint8, XCP_VAR) Xcp_pgm_blockSeqCounter = 0x01u;
#define XCP_STOP_SEC_VAR_INIT_8
#include "XCP_MemMap.h"

#define XCP_START_SEC_VAR_CLEARED_8
#include "XCP_MemMap.h"
/* program_clear and program pending task retry counters */
static VAR(uint8, XCP_VAR) Xcp_Program_retryCounters;
#define XCP_STOP_SEC_VAR_CLEARED_8
#include "XCP_MemMap.h"

/*static VAR(Xcp_ConnectStatusType, memclass) Xcp_ConnectStatus = XCP_UINIT;*/
#define XCP_START_SEC_VAR_INIT_BOOLEAN
#include "XCP_MemMap.h"
static VAR(boolean, XCP_VAR) Xcp_pgm_lastWriteFlag = FALSE;
#define XCP_STOP_SEC_VAR_INIT_BOOLEAN
#include "XCP_MemMap.h"
/*=======[I N T E R N A L   F U N C T I O N   D E C L A R A T I O N S]========*/
#define XCP_START_SEC_CODE
#include "XCP_MemMap.h"
static FUNC(Std_ReturnType,XCP_CODE) Xcp_Program_ZeroHandle(void);

static FUNC(Std_ReturnType,XCP_CODE) Xcp_Program_NonZero(uint32 startAddr, uint8 dataCount, uint8 pgmSize);

static FUNC(Xcp_SeqCheckType,XCP_CODE)
#if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
Xcp_GetPgmStartAddr_SeqCheck
(uint8 pgmSeq, P2VAR(uint32, AUTOMATIC, XCP_VAR) startAddr,
		uint8 noOfBytes);
#else
Xcp_GetPgmStartAddr_SeqCheck
(P2VAR(uint32, AUTOMATIC, XCP_VAR) startAddr,uint8 noOfBytes);
#endif

static FUNC(Xcp_SeqCheckType,XCP_CODE) Xcp_GetPgm_Functional_StartAddr
    (P2VAR(uint32, AUTOMATIC, XCP_VAR) startAddr, uint8 noOfBytes,Xcp_FlashAearType rangType);

static FUNC(Xcp_SeqCheckType,XCP_CODE)
#if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
Xcp_GetPgmClearStartAddr_SeqCheck
(uint32 clearRange,uint32 *startAddr,
 uint32 *clearSize,uint8 maxseqInClearedSectors,
 uint8 maxSeqInPgmedSectors);
#else
Xcp_GetPgmClearStartAddr_SeqCheck
(uint32 clearRange,uint32 *startAddr,
 uint32 *clearSize);
#endif

/* the next six functions used for pending handle */
static FUNC(void,XCP_CODE) Xcp_FlsClearPending(void);

static FUNC(void,XCP_CODE) Xcp_FlsClearTask(void);

static FUNC(void,XCP_CODE) Xcp_FlsProgramPending(void);

static FUNC(void,XCP_CODE) Xcp_FlsProgramTask(void);

#if (XCP_MASTER_BLOCK_MODE == STD_ON)
static FUNC(void,XCP_CODE) Xcp_FlsBlockProgramPending(void);

static FUNC(void,XCP_CODE) Xcp_FlsBlockProgramTask(void);
#endif /* (XCP_MASTER_BLOCK_MODE == STD_ON) */

/*
 * Complex Command Handler
 */
static FUNC(void, XCP_CODE) Xcp_ProgramHal(void);
#if (XCP_PROGRAM_MAX == STD_ON)
static FUNC(void, XCP_CODE) Xcp_ProgramMaxHal(void);
#endif

#if (XCP_PAG_SUPPORT == STD_ON)
#if (XCP_MMU_SUPPORT == STD_ON)
static FUNC(void, XCP_CODE) Xcp_PageProtect(uint8 pid);
#endif
#endif
#define XCP_STOP_SEC_CODE
#include "XCP_MemMap.h"
/*=======[F U N C T I O N   I M P L E M E N T A T I O N S]====================*/
/* local */

#define XCP_START_SEC_CODE
#include "XCP_MemMap.h"

/* Get Program status in external places */
Std_ReturnType Xcp_InPgmStatus(void)
{
    Std_ReturnType blReturn = E_OK;

    if (0x0 == Xcp_pgmPendingFlag)
        blReturn = E_NOT_OK;
    return blReturn;
}
/******************************************************************************/
/*
 * @brief               <Xcp_Program_ZeroHandle>
 *
 * <This function handle when program zero received> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Not Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/

static FUNC(Std_ReturnType,XCP_CODE) Xcp_Program_ZeroHandle(void)
{
	Xcp_PgmBufferIndexType cnt = 0;
    Std_ReturnType programRet = E_NOT_OK;

    if (0u != Xcp_flsBufferSize)
    {
        /* if remained data more than min write size,there should be a error */
        if (Xcp_flsBufferSize >= XCP_FLS_MIN_WRITE_SIZE)
        {
            programRet = E_NOT_OK;

        }
        else
        {
            for (cnt = 0u; cnt < (XCP_FLS_MIN_WRITE_SIZE - Xcp_flsBufferSize); cnt++)
    	    {
    			Xcp_flsBuffer[Xcp_flsBufferSize + cnt] = XCP_PGM_FILLER;
    	    }

            /* set fls buffer size to min write size for pending task */
             Xcp_flsBufferSize = XCP_FLS_MIN_WRITE_SIZE;

            /* set block seq number or MTA */
            if (XCP_FUNCTIONAL_ACCESS == Xcp_Program_AccessMode)
            {
                Xcp_pgm_blockSeqCounter ++;
            }
            if (XCP_ABSOLUTE_ACCESS == Xcp_Program_AccessMode)
            {
                Xcp_UpdateMTA((uint32)XCP_FLS_MIN_WRITE_SIZE);
            }

            /* indicate that this time is the last write of this program sequence */
            Xcp_pgm_lastWriteFlag = TRUE;

    	    if (E_OK == Xcp_FlsReq(XCP_FLS_WRITE, Xcp_flsTargetAddr, XCP_FLS_MIN_WRITE_SIZE, Xcp_flsBuffer))
    		{
                Xcp_pgmPendingFlag |= XCP_PROGRAM_PENDING;
            }
            else
            {
                /* set the state to do flash program action */
                Xcp_pgmPendingFlag |= XCP_PROGRAM_TASK;
            }

    	    programRet = E_OK;
        }
    }
    else
    {
        /* Xcp_flsBuffer empty and program finished */
        Xcp_PgmStauts = XCP_PGM_PROGRAMMED;
        programRet = E_OK;
    }
    return programRet;
}

/******************************************************************************/
/*
 * @brief               <Xcp_GetPgmStartAddr_SeqCheck>
 *
 * < this function do program sequence check do get the program start address> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Not Reentrant>
 * @param[in]           <noOfBytes>
 * @param[out]          <None>
 * @param[in/out]       <startAddr>
 * @return              <Xcp_SeqCheckType>
 */
/******************************************************************************/

static FUNC(Xcp_SeqCheckType,XCP_CODE)
#if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
Xcp_GetPgmStartAddr_SeqCheck
    (uint8 pgmSeq, P2VAR(uint32, AUTOMATIC, XCP_VAR) startAddr, uint8 noOfBytes)
#else
Xcp_GetPgmStartAddr_SeqCheck
    (P2VAR(uint32, AUTOMATIC, XCP_VAR) startAddr, uint8 noOfBytes)
#endif
{
    uint8 sectorNum = 0;
    Xcp_SeqCheckType programSeqcheckRet = SEQ_OK;
    boolean programFlashAreaFind = FALSE;

    /* check the access mode */
    switch (Xcp_Program_AccessMode)
    {
        case XCP_FUNCTIONAL_ACCESS:
        {
            #if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
            /* loop all config sectors to find the corrent one for current programing */
            for (sectorNum = 0u; sectorNum < XCP_MAX_SECTOR; sectorNum++)
            {
                /* find the correct sector which has the min seqence No */
                if (pgmSeq == Xcp_SectorInfo[sectorNum].sectorPgmSequenceNo)
                {
                    programFlashAreaFind = TRUE;
                    *startAddr = Xcp_SectorInfo[sectorNum].progStartAddr;

                    /* check the address */
                    if ((0x00u != Xcp_flsBufferSize)
                    && ((Xcp_flsBufferSize + Xcp_flsTargetAddr) != (*startAddr)))
                    {
                        /* data remained before, but the address not continuous,
                         * so clear the size to 0.
                         */
                        Xcp_flsBufferSize = 0;
                        programSeqcheckRet = SEQ_ERROR;
                    }
                    else if (CHECK_XCP_FLASH_ROM_MEM(*startAddr,noOfBytes,sectorNum))
                    {
                        /* indicate this sector info has already got for prog, so clear Cleared flag */
                        Xcp_sectorCleared[sectorNum] = FALSE;
                        /* and set Programed flag */
                        Xcp_sectorProgramed[sectorNum] = TRUE;
                        /* Clear the area range flag cause we already find it */
                        XCP_flashAreaSelect &= ~(Xcp_SectorInfo[sectorNum].rangeType);
                    }
                    else
                    {
                        programSeqcheckRet = SEQ_OUTRANGE;
                    }
                }/*end of if (pgmSeq == Xcp_SectorInfo[sectorNum].sectorPgmSequenceNo) */
            }/* end of for (sectorNum = 0u ; sectorNum < XCP_MAX_SECTOR; sectorNum++) */
            if (TRUE != programFlashAreaFind)
            {
                programSeqcheckRet = SEQ_ERROR;
            }

            #else
            if (XCP_FLASHAREA_CAL == (XCP_flashAreaSelect | XCP_FLASHAREA_CAL))
            {
                programSeqcheckRet = Xcp_GetPgm_Functional_StartAddr(startAddr,
                                        noOfBytes,(Xcp_FlashAearType)XCP_FLASHAREA_CAL);
            }
            else if (XCP_FLASHAREA_CODE == (XCP_flashAreaSelect | XCP_FLASH_RANGE_CODE))
            {
                programSeqcheckRet = Xcp_GetPgm_Functional_StartAddr(startAddr,
                                        noOfBytes,(Xcp_FlashAearType)XCP_FLASH_RANGE_CODE);
            }
            else if (XCP_FLASHAREA_NVRAM == (XCP_flashAreaSelect | XCP_FLASHAREA_NVRAM))
            {
                programSeqcheckRet = Xcp_GetPgm_Functional_StartAddr(startAddr,
                                        noOfBytes,(Xcp_FlashAearType)XCP_FLASHAREA_NVRAM);
            }
            else
            {
                /* PROGRAM_CLEAR use absolute mode,but program use functional access mode */
                for (sectorNum = 0u; sectorNum < XCP_MAX_SECTOR; sectorNum++)
                {
                    /* find the last erased sector for program */
                    if (Xcp_clearStartAddr == Xcp_SectorInfo[sectorNum].sectorclrStartAddr)
                    {
                        programFlashAreaFind = TRUE;

                        *startAddr = Xcp_SectorInfo[sectorNum].progStartAddr;
                        /* check the address */
                        if ((0x00u != Xcp_flsBufferSize)
                        && ((Xcp_flsBufferSize + Xcp_flsTargetAddr) != (*startAddr)))
                        {
                            /* data remained before, but the address not continuous,
                             * so clear the size to 0.
                             */
                            Xcp_flsBufferSize = 0;
                            programSeqcheckRet = SEQ_ERROR;
                        }
                        else if (CHECK_XCP_FLASH_ROM_MEM(*startAddr, noOfBytes,sectorNum))
                        {
                            programSeqcheckRet = SEQ_OK;
                        }
                        else
                        {
                           programSeqcheckRet = SEQ_OUTRANGE;
                        }
                    }/* end of if (Xcp_clearStartAddr == Xcp_SectorInfo[sectorNum].sectorclrStartAddr)*/
                }/*end of for (sectorNum = 0u; sectorNum < XCP_MAX_SECTOR; sectorNum++)*/
            }/* end of else */
            if (TRUE != programFlashAreaFind)
            {
                programSeqcheckRet = SEQ_ERROR;
            }
            #endif
            break;
        }
        /* Absolute access mode ,then get the clear start address form MTA */
        case XCP_ABSOLUTE_ACCESS:
        {
            /*get address form MTA[0]*/
            *startAddr = Xcp_Mta2Ptr(Xcp_MTA.extensionAddr,Xcp_MTA.transferAddr);
            for (sectorNum = 0u ; sectorNum < XCP_MAX_SECTOR; sectorNum++)
            {
                /* get the program start address if clear used absolute mode */
                #if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
                if (pgmSeq == Xcp_SectorInfo[sectorNum].sectorPgmSequenceNo)
                #else
                if (Xcp_clearStartAddr == Xcp_SectorInfo[sectorNum].sectorclrStartAddr)
                #endif
                {
                    programFlashAreaFind = TRUE;
                    /* check the address */
                    if ((0x00u != Xcp_flsBufferSize)
                    && ((Xcp_flsBufferSize + Xcp_flsTargetAddr) != (*startAddr)))
                    {
                        /* data remained before, but the address not continuous,
                         * so clear the size to 0.
                         */
                        Xcp_flsBufferSize = 0;
                        programSeqcheckRet = SEQ_ERROR;
                    }
                    /* check whether the program start address + noOfBytes out of range */
                    else
                    {
						if (CHECK_XCP_FLASH_ROM_MEM(*startAddr, noOfBytes,sectorNum))
						{
							#if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
							/* indicate this sector info has already got for prog, so clear Cleared flag */
							Xcp_sectorCleared[sectorNum] = FALSE;
							/* and set Programed flag */
							Xcp_sectorProgramed[sectorNum] = TRUE;
							#endif
							programSeqcheckRet = SEQ_OK;
						}
						else
						{
							 programSeqcheckRet = SEQ_OUTRANGE;
						}
                    }
                }
            }
            if (TRUE != programFlashAreaFind)
            {
                programSeqcheckRet = SEQ_ERROR;
            }
            break;
        }
        default:
        {
            programSeqcheckRet = SEQ_ERROR;
            break;
        }
    }
    return programSeqcheckRet;
}

/******************************************************************************/
/*
 * @brief               <Xcp_GetPgm_Functional_StartAddr>
 * < This function find the program start address when use functional access
 * mode >
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <pgmSeq, startAddr,noOfBytes,rangType>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <Xcp_SeqCheckType>
 */
/******************************************************************************/
static FUNC(Xcp_SeqCheckType,XCP_CODE) Xcp_GetPgm_Functional_StartAddr
    (P2VAR(uint32, AUTOMATIC, XCP_VAR) startAddr, uint8 noOfBytes,Xcp_FlashAearType rangType)
{
    uint8 sectorNum = 0;
    boolean rightSectorFind = FALSE;
    Xcp_SeqCheckType ret = SEQ_ERROR;

    /* loop all config sectors to find the correct one for current programming */
    for (sectorNum = 0u ; sectorNum < XCP_MAX_SECTOR; sectorNum++)
    {
        /* check the sector whether has the right range type */
        if ((Xcp_SectorInfo[sectorNum].rangeType == rangType))
        {
        	if(XCP_FLASH_RANGE_CAL == rangType)
        	{
				rightSectorFind = TRUE;
				*startAddr = Xcp_SectorInfo[sectorNum].progStartAddr;

				/* check the address */
				if ((0x00u != Xcp_flsBufferSize)
				&& ((Xcp_flsBufferSize + Xcp_flsTargetAddr) != (*startAddr)))
				{
					/* data remained before, but the address not continuous,
					 * so clear the size to 0.
					 */
					Xcp_flsBufferSize = 0;
					ret = SEQ_ERROR;
				}
				else if (CHECK_XCP_FLASH_ROM_MEM(*startAddr,noOfBytes,sectorNum))
				{
					#if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
					/* indicate this sector info has already got for prog, so clear Cleared flag */
					Xcp_sectorCleared[sectorNum] = FALSE;
					/* and set Programed flag */
					Xcp_sectorProgramed[sectorNum] = TRUE;
					#endif
					ret = SEQ_OK;
					/* Clear the area range flag cause we already find it */
					XCP_flashAreaSelect &= ~(uint32)rangType;
				}
				else
				{
					 ret = SEQ_OUTRANGE;
				}
        	}
        	else if(XCP_FLASH_RANGE_CODE == rangType)
        	{
        		/* XCP_FLASH_RANGE_CODE is not currently supported */
        	}
        	else if(XCP_FLASH_RANGE_NVRAM == rangType)
        	{
        		/* XCP_FLASH_RANGE_NVRAM is not currently supported */
        	}
        	else
        	{
        		/* do nothing */
        	}

        }
    }
    if (TRUE != rightSectorFind)
    {
      ret = SEQ_ERROR;
    }

    return ret;
}


/******************************************************************************/
/*
 * @brief               <Xcp_Program_NonZero>
 *
 * < This function handled when not a program zero command received > .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <startAddr, dataCount,pgmSize>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <Std_ReturnType>
 */
/******************************************************************************/
static FUNC(Std_ReturnType,XCP_CODE) Xcp_Program_NonZero(uint32 startAddr, uint8 dataCount, uint8 pgmSize)
{
    uint8 dataNo = 0;
    Std_ReturnType result = E_OK;

    if (dataCount <= pgmSize)
    {
        if (0u == Xcp_flsBufferSize)
        {
            Xcp_flsTargetAddr = startAddr;
        }
    	for (dataNo = 0u; dataNo < dataCount; dataNo++)
    	{
    	    if (XCP_PROGRAMMAX_SIZE == pgmSize)
    		{
    		    /* program_Max command copy the Cmdbuffer data to Xcp_flsBuffer from XCP_AG position */
                Xcp_flsBuffer[Xcp_flsBufferSize + dataNo] = Xcp_CmdBuffer[XCP_AG + dataNo];
            }
            else
            {
                #if (XCP_ADDRESS_GRANULARITY != XCP_AG_DWORD)
    		    Xcp_flsBuffer[Xcp_flsBufferSize + dataNo] = Xcp_CmdBuffer[2u + dataNo];
                #else
    		    Xcp_flsBuffer[Xcp_flsBufferSize + dataNo] = Xcp_CmdBuffer[XCP_AG + dataNo];
                #endif
            }
    	}
        Xcp_flsBufferSize += dataCount;

        if (XCP_FUNCTIONAL_ACCESS == Xcp_Program_AccessMode)
        {
            Xcp_pgm_blockSeqCounter ++;
        }
        else if (XCP_ABSOLUTE_ACCESS == Xcp_Program_AccessMode)
        {
            Xcp_UpdateMTA((uint32)dataCount);
        }
        else
        {
            /* Do Nothing */
        }

        /* check the buffer size , bigger than XCP_FLS_MIN_WRITE_SIZE, then do write */
        if (Xcp_flsBufferSize >= XCP_FLS_MIN_WRITE_SIZE)
        {
    	    if (E_OK == Xcp_FlsReq(XCP_FLS_WRITE, Xcp_flsTargetAddr, XCP_FLS_MIN_WRITE_SIZE, Xcp_flsBuffer))
    		{
                Xcp_pgmPendingFlag |= XCP_PROGRAM_PENDING;
            }
            else
            {
                Xcp_pgmPendingFlag |= XCP_PROGRAM_TASK;
            }
    	}
    }
    /* write data size bigger than pgmSize */
    else
    {
        result = E_NOT_OK;
    }
    return result;
}

/******************************************************************************/
/*
 * @brief               <Xcp_GetPgmClearStartAddr_SeqCheck>
 *
 * < This funtion check the clear sequence when check option enabled
    and get the program_clear start address and size > .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <clearRange, maxseqInClearedSectors,maxSeqInPgmedSectors>
 * @param[out]          <startAddr, clearSize>
 * @param[in/out]       <None>
 * @return              <Xcp_SeqCheckType>
 */
/******************************************************************************/
static FUNC(Xcp_SeqCheckType,XCP_CODE)
#if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
Xcp_GetPgmClearStartAddr_SeqCheck
(uint32 clearRange, P2VAR(uint32, AUTOMATIC, XCP_VAR) startAddr,
 P2VAR(uint32, AUTOMATIC, XCP_VAR)clearSize, uint8 maxseqInClearedSectors,
 uint8 maxSeqInPgmedSectors)
#else
Xcp_GetPgmClearStartAddr_SeqCheck
(uint32 clearRange,P2VAR(uint32, AUTOMATIC, XCP_VAR) startAddr,
 P2VAR(uint32, AUTOMATIC, XCP_VAR) clearSize)
#endif
{
    uint8 sectorNum = 0;
    Xcp_SeqCheckType result = SEQ_OK;
    boolean programClearModeFind = FALSE;

    /* functional access mode ,then calculate the clear start address */
    if (XCP_FUNCTIONAL_ACCESS == Xcp_Clear_AccessMode)
    {
       /* select the flash area need to clear,
        * Provide the flag for PROGRAM used when in functional access mode
        */
        XCP_flashAreaSelect |= clearRange;

        for (sectorNum = 0u ; sectorNum < XCP_MAX_SECTOR; sectorNum++)
        {
            /* get the clear start address by clear range */
            if (Xcp_SectorInfo[sectorNum].rangeType == (Xcp_FlashAearType)clearRange)
            {
            	if(XCP_FLASH_RANGE_CAL == (Xcp_FlashAearType)clearRange)
            	{
					programClearModeFind = TRUE;

					/* Get the info for clear */
					*startAddr = Xcp_SectorInfo[sectorNum].sectorclrStartAddr;
					*clearSize = Xcp_SectorInfo[sectorNum].sectorclrLength;

					/* if the current clear sequence number less then seq No of the sectors that cleared before
					 * or less than the seq No of the sector that been programed before,this indicate the current
					 * sector should be clear and program eariler,so it's a sequence error
					 */
					#if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
					if ((Xcp_SectorInfo[sectorNum].sectorclrSequenceNo < maxseqInClearedSectors)
					   ||(Xcp_SectorInfo[sectorNum].sectorclrSequenceNo < maxSeqInPgmedSectors))
					{
						/* clear seqence error ocuured */
						result = SEQ_ERROR;
					}
					else
					{
					   /* indicate this sector has been selected for cleared*/
						Xcp_sectorCleared[sectorNum] = TRUE;
					}
					#endif
            	}
            	else if(XCP_FLASH_RANGE_CODE == (Xcp_FlashAearType)clearRange)
            	{
            		/* XCP_FLASH_RANGE_CODE is not currently supported */
            	}
            	else if(XCP_FLASH_RANGE_NVRAM == (Xcp_FlashAearType)clearRange)
            	{
            		/* XCP_FLASH_RANGE_NVRAM is not currently supported */
            	}
            	else
            	{
            		/* do nothing */
            	}

            }
        }
        /* We do not find the clear area*/
        if (TRUE != programClearModeFind)
        {
             result = SEQ_OUTRANGE;
        }

    }
    /* Absolute access mode ,then get the clear start address form MTA */
    else if (XCP_ABSOLUTE_ACCESS == Xcp_Clear_AccessMode)
    {
        /*get address form MTA[0]*/
         *startAddr = Xcp_Mta2Ptr(Xcp_MTA.extensionAddr,Xcp_MTA.transferAddr);

         for (sectorNum = 0u ; sectorNum < XCP_MAX_SECTOR; sectorNum++ )
         {
            /* get the clear start address by clear range */
            if (Xcp_SectorInfo[sectorNum].progStartAddr == *startAddr)
            {
                 programClearModeFind = TRUE;
                *startAddr = Xcp_SectorInfo[sectorNum].sectorclrStartAddr;
                /* if the current clear sequence number less then seq No of the sectors that cleared before
                 * or less than the seq No of the sector that been programed before,this indicate the current
                 * sector should be clear and program eariler,so it's a sequence error
                 */
                #if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
                if ((Xcp_SectorInfo[sectorNum].sectorclrSequenceNo < maxseqInClearedSectors)
                   ||(Xcp_SectorInfo[sectorNum].sectorclrSequenceNo < maxSeqInPgmedSectors))
                {
                    /* clear seqence error ocuured */
                     result = SEQ_ERROR;
                }
                else
                {
                   /* indicate this sector has been selected gor cleared*/
                    Xcp_sectorCleared[sectorNum] = TRUE;
                }
                #endif
                if (clearRange <= Xcp_SectorInfo[sectorNum].sectorclrLength)
                {
                    /*get pram. clear size from CRO buffer*/
                    *clearSize = Xcp_SectorInfo[sectorNum].sectorclrLength;
                }
                else
                {
                    result = SEQ_DENIED;
                }
                break;
            }
        }
        /* We do not find the clear area*/
        if (TRUE != programClearModeFind)
        {
            result = SEQ_OUTRANGE;
        }
    }
    else
    {
        /* neither ABSOLUTE nor FUNCTIONAL mode */
         result = SEQ_OUTRANGE;
    }
    return  result;
}

/******************************************************************************/
/*
 * @brief               <Xcp_FlsClearPending>
 *
 * < This funtion do pending task when pendingFlag is clearPending > .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
static FUNC(void, XCP_CODE) Xcp_FlsClearPending(void)
{
    uint8 result = 0;
    result = Xcp_FlsGetStatus();
    switch(result)
    {
        case XCP_IF_OK:
            Xcp_pgmPendingFlag &= (uint8)(~XCP_CLEAR_PENDING);
            Xcp_flsBufferSize = 0u;
            /* set the program status as XCP_PGM_CLEARED */
            Xcp_PgmStauts = XCP_PGM_CLEARED;
            Xcp_SendResp();
            break;
        case XCP_IF_NOT_OK:
            Xcp_pgmPendingFlag &= (uint8)(~XCP_CLEAR_PENDING);
            Xcp_flsBufferSize = 0u;

            /* Do not set the program status because clear failed */

            Xcp_SetErrorCode(XCP_ERR_RES_TEMP_NOT_A);
            Xcp_RespLength = 0x02u;
            Xcp_SendResp();
            break;
        default:
            break;
    }
    return;
}

/******************************************************************************/
/*
 * @brief               <Xcp_FlsClearTask>
 *
 * < This funtion do pending task when pendingFlag is clearTask > .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
static FUNC(void, XCP_CODE) Xcp_FlsClearTask(void)
{
    if (E_OK == Xcp_FlsReq(XCP_FLS_ERASE, Xcp_clearStartAddr,
                                       Xcp_clearSize, NULL_PTR))
    {
        Xcp_Program_retryCounters = 0u;
        Xcp_pgmPendingFlag &= (uint8)(~XCP_CLEAR_TASK);
        Xcp_pgmPendingFlag |= XCP_CLEAR_PENDING;
    }
    else
    {
        Xcp_Program_retryCounters++;
        if (Xcp_Program_retryCounters >= XCP_PGM_REQRETRIE)
        {
            Xcp_Program_retryCounters = 0u;
            Xcp_pgmPendingFlag &= (uint8)(~XCP_CLEAR_TASK);
            Xcp_SetErrorCode(XCP_ERR_RES_TEMP_NOT_A);
            Xcp_RespLength = 0x02u;
            Xcp_SendResp();
        }
        else
        {
            /* do nothing */
        }
    }
    return;
}

/******************************************************************************/
/*
 * @brief               <Xcp_FlsProgramPending>
 *
 * < This funtion do pending task when pendingFlag is programPending > .
 * Service ID   :       <None>
 * Sync/Async   :       <None>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
static FUNC(void, XCP_CODE) Xcp_FlsProgramPending(void)
{
    uint8 result = 0;
    Xcp_PgmBufferIndexType cnt = 0;
    result = Xcp_FlsGetStatus();
    switch(result)
    {
        case XCP_IF_OK:
            Xcp_pgmPendingFlag &= (uint8)(~XCP_PROGRAM_PENDING);

            Xcp_flsTargetAddr += XCP_FLS_MIN_WRITE_SIZE;
		    Xcp_flsBufferSize -= XCP_FLS_MIN_WRITE_SIZE;

            if (TRUE == Xcp_pgm_lastWriteFlag)
            {
               Xcp_PgmStauts = XCP_PGM_PROGRAMMED;

               /* program completed, clear buffer size */
               Xcp_flsBufferSize = 0x0u;

               /* clear the last write flag */
               Xcp_pgm_lastWriteFlag = FALSE;
            }
            /* Copy more than XCP_FLS_MIN_WRITE_SIZE bytes after the data */
			for (cnt = 0u; cnt < Xcp_flsBufferSize ; cnt++)
			{
				Xcp_flsBuffer[cnt] = Xcp_flsBuffer[cnt + XCP_FLS_MIN_WRITE_SIZE];
			}
            if (Xcp_flsBufferSize >= XCP_FLS_MIN_WRITE_SIZE)
            {
                Xcp_pgmPendingFlag |= XCP_PROGRAM_TASK;
            }
            else
            {
                Xcp_SendResp();
            }
            break;
        case XCP_IF_NOT_OK:
            Xcp_pgmPendingFlag &= (uint8)(~XCP_PROGRAM_PENDING);
            Xcp_flsBufferSize = 0;

            /* set the program status back to XCP_PGM_START because program failed, and Need to be re-erased */
            Xcp_PgmStauts = XCP_PGM_START;

            Xcp_SetErrorCode(XCP_ERR_RES_TEMP_NOT_A);
            Xcp_RespLength = 0x02u;
            Xcp_SendResp();
            break;
        default:
            break;
    }
    return;
}

/******************************************************************************/
/*
 * @brief               <Xcp_FlsProgramTask>
 *
 * < This funtion do pending task when pendingFlag is programTask > .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
static FUNC(void, XCP_CODE) Xcp_FlsProgramTask(void)
{
    if (E_OK == Xcp_FlsReq(XCP_FLS_WRITE, Xcp_flsTargetAddr,
                     XCP_FLS_MIN_WRITE_SIZE, Xcp_flsBuffer))
    {
        Xcp_Program_retryCounters = 0u;
        Xcp_pgmPendingFlag &= (uint8)(~XCP_PROGRAM_TASK);
        Xcp_pgmPendingFlag |= XCP_PROGRAM_PENDING;
    }
    else
    {
        Xcp_Program_retryCounters++;
        if (Xcp_Program_retryCounters >= XCP_PGM_REQRETRIE)
        {
            Xcp_Program_retryCounters = 0u;
            Xcp_pgmPendingFlag &= (uint8)(~XCP_PROGRAM_TASK);
            Xcp_flsBufferSize = 0u;
            Xcp_SetErrorCode(XCP_ERR_RES_TEMP_NOT_A);
            Xcp_RespLength = 0x02u;
            Xcp_SendResp();
        }
        else
        {
            /* counter no expired , do nothing */
        }
    }
    return;
}

#if (XCP_MASTER_BLOCK_MODE == STD_ON)
/******************************************************************************/
/*
 * @brief               <Xcp_FlsBlockProgramPending>
 *
 * < This funtion do pending task when pendingFlag is BlockprogramPending > .
 * Service ID   :       <None>
 * Sync/Async   :       <None>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
static FUNC(void, XCP_CODE) Xcp_FlsBlockProgramPending(void)
{
    uint8 result = 0;
    Xcp_PgmBufferIndexType cnt = 0;
    result = Xcp_FlsGetStatus();
    switch(result)
    {
        case XCP_IF_OK:
            Xcp_pgmPendingFlag &= (uint8)(~XCP_BLOCK_PROGRAM_PENDING);

            /* set the program status as XCP_PGM_PROGRAMMING */
            Xcp_PgmStauts = XCP_PGM_PROGRAMMING;

            Xcp_flsTargetAddr += XCP_FLS_MIN_WRITE_SIZE;
            /* if remained data more than min write size ,then continue write*/
            if ((XCP_FLS_MIN_WRITE_SIZE + Xcp_BlockBufferPos) <= Xcp_BlockBufferLen)
            {
                for (cnt = 0u; cnt < XCP_FLS_MIN_WRITE_SIZE; cnt++)
        	    {
                    Xcp_flsBuffer[cnt] = Xcp_BlockBuffer[Xcp_BlockBufferPos + cnt];
        	    }
                /* set fls buffer size to min write size */
                Xcp_flsBufferSize = XCP_FLS_MIN_WRITE_SIZE;

                Xcp_BlockBufferPos += XCP_FLS_MIN_WRITE_SIZE;

                Xcp_pgmPendingFlag |= XCP_BLOCK_PROGRAM_TASK;
                Xcp_UpdateMTA((uint32)XCP_FLS_MIN_WRITE_SIZE);

            }
            else
            {
                for (cnt = 0u; Xcp_BlockBufferLen != Xcp_BlockBufferPos; cnt++)
        	    {
                    Xcp_flsBuffer[cnt] = Xcp_BlockBuffer[Xcp_BlockBufferPos];
                    Xcp_BlockBufferPos++;
        	    }
                Xcp_flsBufferSize = cnt;
                Xcp_UpdateMTA((uint32)cnt);

                Xcp_SendResp();
            }

            break;
        case XCP_IF_NOT_OK:
            Xcp_pgmPendingFlag &= (uint8)(~XCP_BLOCK_PROGRAM_PENDING);

            /* set the program status back to XCP_PGM_START because program failed */
            Xcp_PgmStauts = XCP_PGM_START;
            Xcp_BlockBufferLen = 0u;
            Xcp_BlockBufferPos = 0u;
            Xcp_SetErrorCode(XCP_ERR_RES_TEMP_NOT_A);
            Xcp_RespLength = 0x02u;
            Xcp_SendResp();
            break;
        default:
            break;
    }
    return;
}

/******************************************************************************/
/*
 * @brief               <Xcp_FlsBlockProgramTask>
 *
 * < This funtion do pending task when pendingFlag is BlockprogramTask > .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
static FUNC(void, XCP_CODE) Xcp_FlsBlockProgramTask(void)
{
    Std_ReturnType result = E_OK;

    result = Xcp_FlsReq(XCP_FLS_WRITE, Xcp_flsTargetAddr,
                     XCP_FLS_MIN_WRITE_SIZE, Xcp_flsBuffer);

    if (E_OK == result)
    {
	    Xcp_Program_retryCounters = 0;
	    Xcp_pgmPendingFlag &= (uint8)(~XCP_BLOCK_PROGRAM_TASK);
        Xcp_pgmPendingFlag |= XCP_BLOCK_PROGRAM_PENDING;

    }
    else
    {
        Xcp_Program_retryCounters++;
        if (Xcp_Program_retryCounters >= XCP_PGM_REQRETRIE)
        {
            Xcp_Program_retryCounters = 0u;
            Xcp_pgmPendingFlag &= (uint8)(~XCP_BLOCK_PROGRAM_TASK);
            #if (XCP_MASTER_BLOCK_MODE == STD_ON)
            Xcp_BlockBufferLen = 0u;
            #endif
            Xcp_SetErrorCode(XCP_ERR_RES_TEMP_NOT_A);
            Xcp_RespLength = 0x02u;
            Xcp_SendResp();
        }
        else
        {
            /* counter no expired, do nothing */
        }
    }
    return;
}
#endif /*XCP_MASTER_BLOCK_MODE == STD_ON*/

#if (XCP_PAG_SUPPORT == STD_ON)
#if (XCP_MMU_SUPPORT == STD_ON)
static FUNC(void, XCP_CODE) Xcp_PageProtect(uint8 pid)
{
	asm volatile (" mtspr 48,%[_val]" : : [_val] "r" (pid));
    return;
}
#endif
#endif


/* gobal */
/******************************************************************************/
/*
 * @brief               <Xcp_ProgramInit>
 *
 * <This function handle the initialise of Program> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE) Xcp_ProgramInit(void)
{
	Xcp_PgmBufferIndexType cnt = 0;
    /*clear all pending task flag*/
    Xcp_pgmPendingFlag = 0x00u;

    for (cnt = 0u; cnt < XCP_FLS_DATA_BUFFER_SIZE; cnt++)
    {
        Xcp_flsBuffer[cnt] = 0xff;
    }
    Xcp_flsBufferSize = 0u;

    Xcp_flsTargetAddr = 0u;

    /* Last write flag will be set while a program zero occurred */
    Xcp_pgm_lastWriteFlag = FALSE;


#if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
    /*init the flag */
    for (cnt = 0u; cnt < XCP_MAX_SECTOR; cnt++)
    {
        Xcp_sectorCleared[cnt] = FALSE;
        Xcp_sectorProgramed[cnt] = FALSE;
    }
#endif

    /*init the pgm statue to IDLE*/
    Xcp_PgmStauts = XCP_PGM_IDLE;
    return;
}

/******************************************************************************/
/*
 * @brief               <Xcp_PgmPendingTask>
 *
 * <This function handle the initialise of Program> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE) Xcp_PgmPendingTask(void)
{
    switch(Xcp_pgmPendingFlag)
    {
        case XCP_CLEAR_PENDING:
        {
            Xcp_FlsClearPending();
            break;
        }
        case XCP_CLEAR_TASK:
        {
            Xcp_FlsClearTask();
            break;
        }
        case XCP_PROGRAM_PENDING:
        {
            Xcp_FlsProgramPending();
            break;
        }
        case XCP_PROGRAM_TASK:
        {
            Xcp_FlsProgramTask();
            break;
        }
        #if (XCP_MASTER_BLOCK_MODE == STD_ON)
        case XCP_BLOCK_PROGRAM_PENDING:
        {
            Xcp_FlsBlockProgramPending();
            break;
        }
        case XCP_BLOCK_PROGRAM_TASK:
        {
            Xcp_FlsBlockProgramTask();
            break;
        }
        #endif /* XCP_MASTER_BLOCK_MODE == STD_ON */
        default:
            break;
    }
    return;
}


/* mandatory */
/******************************************************************************/
/*
 * @brief               <Xcp_ProgramStart>
 *
 * <start a program sequence> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE) Xcp_ProgramStart(void)
{
    Std_ReturnType result = E_NOT_OK;

    #if (XCP_PAG_SUPPORT == STD_ON)
    #if (XCP_MMU_SUPPORT == STD_ON)
    uint8 segNum;
    #endif
    #endif


    #if ((STD_OFF == XCP_CAN_MAX_DLC_REQUIRED) && (STD_ON == XCP_ON_CAN_ENABLE))
    if ((Xcp_CmdLength != 1u)
    && (Xcp_CmdLength != XCP_CAN_MAX_DLC))
    {
        Xcp_SetErrorCode(XCP_ERR_CMD_SYNTAX);
        Xcp_RespLength = 0x02u;
    }
    else
    #endif
    {
        /* check whether DAQ Running at this moment */
        if (XCP_SESSION_STATE_DAQ_RUNNING == (Xcp_SessionStatus & XCP_SESSION_STATE_DAQ_RUNNING))
        {
             Xcp_SetErrorCode(XCP_ERR_DAQ_ACTIVE);
             Xcp_RespLength = 0x02u;
        }
        /* check the protection status */
        else if (XCP_PL_PGM == (Xcp_ProtectionStatus & XCP_PL_PGM))
        {
            Xcp_SetErrorCode(XCP_ERR_ACCESS_LOCKED);
            Xcp_RespLength = 0x02u;
        }
        else
        {
            /* call out function to notice app that program start*/
            result = Xcp_ProgramStartNoticeApp();
            if (E_NOT_OK == result)
            {
                Xcp_SetErrorCode(XCP_ERR_RES_TEMP_NOT_A);
                Xcp_RespLength = 0x02u;
            }
            else
            {
                /* when start flash turn the page to the RAM */
                #if (XCP_PAG_SUPPORT == STD_ON)
                #if (XCP_MMU_SUPPORT == STD_ON)
                Xcp_PageProtect(XCP_RAM_PAGE_PID);
                for (segNum = 0; segNum < Xcp_SegmentInfo.maxSegNum; segNum++)
                {
                    Xcp_ActivPagNum[segNum] = XCP_RAM_PAGE_NUM;
                }
                #endif
                #endif

                Xcp_RespBuffer[2u] = 0;
                #if (XCP_MASTER_BLOCK_MODE == STD_ON)
                Xcp_RespBuffer[2u] |= 0x01u;
                #endif
                #if (XCP_INTERLEAVED_MODE == STD_ON)
                Xcp_RespBuffer[2u] |= 0x02u;
                #endif
				#if (XCP_SLAVE_BLOCK_MODE == STD_ON)
				Xcp_RespBuffer[2u] |= 0x40u;
				#endif
                Xcp_RespBuffer[3u] = XCP_MAX_CTO_PGM;
                #if (XCP_MASTER_BLOCK_MODE == STD_ON)
                Xcp_RespBuffer[4u] =XCP_MAX_BS_PGM;
                Xcp_RespBuffer[5u] =XCP_MIN_ST_PGM;
                #else
                Xcp_RespBuffer[4u] = 0;
                Xcp_RespBuffer[5u] = 0;
                #endif
                #if (XCP_INTERLEAVED_MODE == STD_ON)
                Xcp_RespBuffer[6u] = XCP_QUEUE_SIZE_PGM;
                #endif
                Xcp_RespLength = 0x07u;
                Xcp_PgmStauts = XCP_PGM_START;
            }
        }
    }
    Xcp_SendResp();
    return;
}


/******************************************************************************/
/*
 * @brief               <Xcp_ProgramClear>
 *
 * <xcp protocol to clear flash,should depend on the clear mode > .
 * Service ID   :       <SERVICE ID>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <void>
 */
/******************************************************************************/
FUNC(void, XCP_CODE) Xcp_ProgramClear(void)
{
    Xcp_SeqCheckType seqResult = SEQ_OK;
    uint32 programClearRange = 0;
    #if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
    uint8 maxClearSeqInClearedSectors = 0u;
    uint8 maxClearSeqInProgramedSectors = 0u;
    uint8 sectorNum = 0;
    #endif


    #if ((STD_OFF == XCP_CAN_MAX_DLC_REQUIRED) && (STD_ON == XCP_ON_CAN_ENABLE))
    if (Xcp_CmdLength != 8u)
    {
        Xcp_SetErrorCode(XCP_ERR_CMD_SYNTAX);
        Xcp_RespLength = 0x02u;
    }
    else
    #endif
    {
        /* check the protection status */
        if (XCP_PL_PGM == (Xcp_ProtectionStatus & XCP_PL_PGM))
        {
             Xcp_SetErrorCode(XCP_ERR_ACCESS_LOCKED);
             Xcp_RespLength = 0x02u;
        }

         /* check the program status */
        else if (XCP_PGM_IDLE == Xcp_PgmStauts)
        {
             Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
             Xcp_RespLength = 0x02u;
        }

        else
        {    /* get the clear mode from CommandRxObject[1] buffer */
            Xcp_Clear_AccessMode = Xcp_CmdBuffer[1u];

             /* get the clear size from CommandRxObject[4]-[7] buffer */
            Xcp_CopyU1BufferToU4(&Xcp_CmdBuffer[4u], &programClearRange, CPU_BYTE_ORDER);

            #if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
            /* find the max clear seq number in  been cleared sectors */
            for (sectorNum = 0u; sectorNum < XCP_MAX_SECTOR; sectorNum++)
            {
                if ((TRUE == Xcp_sectorCleared[sectorNum])
                && (Xcp_SectorInfo[sectorNum].sectorclrSequenceNo > maxClearSeqInClearedSectors))
                {
                    maxClearSeqInClearedSectors = Xcp_SectorInfo[sectorNum].sectorclrSequenceNo;
                }
            }
            /* find the max clear seq number in  been programed sectors */
            for (sectorNum = 0u; sectorNum < XCP_MAX_SECTOR; sectorNum++ )
            {
                if ((TRUE == Xcp_sectorProgramed[sectorNum])
                && (Xcp_SectorInfo[sectorNum].sectorclrSequenceNo > maxClearSeqInProgramedSectors))
                {
                    maxClearSeqInProgramedSectors = Xcp_SectorInfo[sectorNum].sectorclrSequenceNo;
                }
            }
            #endif /* (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON) */

            /* check the clear sequence and get the clear start address and size */
            #if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
            seqResult = Xcp_GetPgmClearStartAddr_SeqCheck(programClearRange,&Xcp_clearStartAddr,&Xcp_clearSize,
                                                    maxClearSeqInClearedSectors,maxClearSeqInProgramedSectors);
            #else
            seqResult = Xcp_GetPgmClearStartAddr_SeqCheck(programClearRange,&Xcp_clearStartAddr,&Xcp_clearSize);
            #endif
            switch (seqResult)
            {
                case SEQ_OK:
                {
                    /* clear Flash it will be done in the pengding task*/
                    if (E_OK == Xcp_FlsReq(XCP_FLS_ERASE, Xcp_clearStartAddr, Xcp_clearSize, NULL_PTR))
                    {
                        Xcp_pgmPendingFlag |= XCP_CLEAR_PENDING;
                    }
                    else
                    {
                        Xcp_pgmPendingFlag |= XCP_CLEAR_TASK;;
                    }
                    break;
                }
                case SEQ_ERROR:
                {
                    Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
                    Xcp_RespLength = 0x02u;
                    break;
                }
                case SEQ_DENIED:
                {
                    Xcp_SetErrorCode(XCP_ERR_ACCESS_DENIED);
                    Xcp_RespLength = 0x02u;
                    break;
                }
                case SEQ_OUTRANGE:
                {
                    Xcp_SetErrorCode(XCP_ERR_OUT_OF_RANGE);
                    Xcp_RespLength = 0x02u;
                    break;
                }
                default:
                {
					/* Do Nothing */
                    break;
                }
           }
        }
    }
    if (0x00 == Xcp_pgmPendingFlag)
    {
        Xcp_SendResp();
    }
    return;
}

static FUNC(void, XCP_CODE) Xcp_ProgramHal(void)
{
    Std_ReturnType result = E_OK;
    Xcp_SeqCheckType seqResult = SEQ_OK;
    uint8 programNumberOfData = 0;
    uint8 NumOfBytes = 0;
    uint32 programStartAddress = 0;
    uint8 sectorNum = 0;
	#if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
    uint8 programSeqTmp = 0xffu;
    /* find the min program sequence number in selected sectors */
    for (sectorNum = 0u; sectorNum < XCP_MAX_SECTOR; sectorNum++)
    {
        if ((TRUE == Xcp_sectorCleared[sectorNum])
        && (Xcp_SectorInfo[sectorNum].sectorPgmSequenceNo < programSeqTmp))
        {
            programSeqTmp = Xcp_SectorInfo[sectorNum].sectorPgmSequenceNo;
        }
    }
    #endif
    /* get the program size from CommandRxObject[1] buffer */
    programNumberOfData = Xcp_CmdBuffer[1u];
    #if (XCP_ADDRESS_GRANULARITY != XCP_AG_DWORD)
    NumOfBytes = 2u + (programNumberOfData * XCP_AG);
    #else
    NumOfBytes = 4u + (programNumberOfData * XCP_AG);
    #endif
    /* The cleanup operation must be performed before programming,so the Xcp_PgmStauts will be XCP_PGM_CLEARED or XCP_PGM_PROGRAMMING */
    if (XCP_PGM_CLEARED == Xcp_PgmStauts)
    {
         /* do porgram sequence check and get program start address */
        #if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
        seqResult = Xcp_GetPgmStartAddr_SeqCheck(programSeqTmp,&programStartAddress,NumOfBytes);
        #else
        seqResult = Xcp_GetPgmStartAddr_SeqCheck(&programStartAddress,NumOfBytes);
        #endif
        if (SEQ_OK == seqResult)
        {
            Xcp_flsTargetAddr = programStartAddress;
            result = Xcp_Program_NonZero(Xcp_flsTargetAddr,programNumberOfData,XCP_PROGRAM_SIZE);
            if (E_OK == result)
            {
                /* set the program status as XCP_PGM_PROGRAMMING */
                Xcp_PgmStauts = XCP_PGM_PROGRAMMING;
            }
            else
            {
                Xcp_SetErrorCode(XCP_ERR_OUT_OF_RANGE);
                Xcp_RespLength = 0x02u;
            }
        }
        else if (SEQ_ERROR == seqResult)/* clear sequence ocuured */
        {
            Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
            Xcp_RespLength = 0x02u;
        }
        else/**< SEQ_OUTRANGE == seqResult */
        {
            Xcp_SetErrorCode(XCP_ERR_ACCESS_DENIED);
            Xcp_RespLength = 0x02u;
        }
    }
    else if(XCP_PGM_PROGRAMMING == Xcp_PgmStauts)
    {
        switch (Xcp_Program_AccessMode)
        {
            case XCP_ABSOLUTE_ACCESS:
            {
                /*get address form MTA[0]*/
                programStartAddress = Xcp_Mta2Ptr(Xcp_MTA.extensionAddr,Xcp_MTA.transferAddr);
                for (sectorNum = 0u; sectorNum < XCP_MAX_SECTOR; sectorNum++)
                {
                    if ((programStartAddress >= Xcp_SectorInfo[sectorNum].progStartAddr)
                    && ((programStartAddress + programNumberOfData) <= (Xcp_SectorInfo[sectorNum].progStartAddr + Xcp_SectorInfo[sectorNum].progDataSize)))
                    {
                        break;
                    }
                }
                if (XCP_MAX_SECTOR == sectorNum)
                {
                    Xcp_flsBufferSize = 0;
                    Xcp_SetErrorCode(XCP_ERR_ACCESS_DENIED);
                    Xcp_RespLength = 0x02u;
                }
                /*if Xcp_flsBufferSize is 0, set Xcp_flsTargetAddr for calibration software(e.g. CANAPE) optimize */
                else if (0x00u == Xcp_flsBufferSize)
                {
                    Xcp_flsTargetAddr = programStartAddress;
                    result = Xcp_Program_NonZero(Xcp_flsTargetAddr,programNumberOfData,XCP_PROGRAM_SIZE);
                }
                else if ((Xcp_flsBufferSize + Xcp_flsTargetAddr) != programStartAddress)
                {
                    /* Xcp_flsBufferSize != 0, but the address not continuous,
                     * so clear the size to 0.
                     */
                    Xcp_flsBufferSize = 0;
                    Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
                    Xcp_RespLength = 0x02u;
                }
                else
                {
                    result = Xcp_Program_NonZero(Xcp_flsTargetAddr,programNumberOfData,XCP_PROGRAM_SIZE);
                }
                break;
            }
            case XCP_FUNCTIONAL_ACCESS:
            {
                result = Xcp_Program_NonZero(Xcp_flsTargetAddr,programNumberOfData,XCP_PROGRAM_SIZE);
                break;
            }
            default:
            {
                result = E_NOT_OK;
                break;
            }
        }
        if (E_NOT_OK == result)
        {
            Xcp_SetErrorCode(XCP_ERR_OUT_OF_RANGE);
            Xcp_RespLength = 0x02u;
        }
    }
    else
    {
    	/* This address is not erased */
    	Xcp_SetErrorCode(XCP_ERR_WRITE_PROTECTED);
    	Xcp_RespLength = 0x02u;
    }
    return;
}

/******************************************************************************/
/*
 * @brief               <Xcp_Program>
 *
 * <xcp prgram the data to flash,it contains block mode or non_block mode> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE) Xcp_Program(void)
{
	Std_ReturnType result = E_OK;
    #if ((STD_OFF == XCP_CAN_MAX_DLC_REQUIRED) && (STD_ON == XCP_ON_CAN_ENABLE))
    if (
    #if (XCP_ADDRESS_GRANULARITY != XCP_AG_DWORD)
    (Xcp_CmdLength != (2u + (Xcp_CmdBuffer[1u] * XCP_AG)))
    #else
    (Xcp_CmdLength != (4u + (Xcp_CmdBuffer[1u] * XCP_AG)))
    #endif
    && (Xcp_CmdLength != XCP_CAN_MAX_DLC))
    {
        Xcp_SetErrorCode(XCP_ERR_CMD_SYNTAX);
        Xcp_RespLength = 0x02u;
    }
    else
    #endif
    /* check the protection status */
    if (XCP_PL_PGM == (Xcp_ProtectionStatus & XCP_PL_PGM))
    {
         Xcp_SetErrorCode(XCP_ERR_ACCESS_LOCKED);
         Xcp_RespLength = 0x02u;
    }
     /* check the program status */
    else if ((XCP_PGM_IDLE == Xcp_PgmStauts) || (XCP_PGM_START == Xcp_PgmStauts))
    {
         Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
         Xcp_RespLength = 0x02u;
    }
    /* check out of range */
    else if (Xcp_CmdBuffer[1u] > XCP_PROGRAM_SIZE)
    {
        Xcp_SetErrorCode(XCP_ERR_OUT_OF_RANGE);
        Xcp_RespLength = 0x02u;
    }
    else
	{
		switch (Xcp_CmdBuffer[1u])
		{
			case 0:
			{
                result = Xcp_Program_ZeroHandle();
				break;
			}
			default:
			{
                Xcp_ProgramHal();
				break;
			}
		}
	}
	if (E_NOT_OK == result)
    {
        Xcp_SetErrorCode(XCP_ERR_CMD_SYNTAX);
        Xcp_RespLength = 0x02u;
    }
    if (0x00 == Xcp_pgmPendingFlag)
    {
        Xcp_SendResp();
    }
    return;
}

/******************************************************************************/
/*
 * @brief               <Xcp_ProgramReset>
 *
 * < when program finished , a program reset command shall be excuted for
    slave disconnect with master > .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE) Xcp_ProgramReset(void)
{
#if ((STD_OFF == XCP_CAN_MAX_DLC_REQUIRED) && (STD_ON == XCP_ON_CAN_ENABLE))
    if ((Xcp_CmdLength != 1u)
    && (Xcp_CmdLength != XCP_CAN_MAX_DLC))
    {
        Xcp_SetErrorCode(XCP_ERR_CMD_SYNTAX);
        Xcp_RespLength = 0x02u;
    }
    else
#endif
    {
         /* check the protection status */
        if (XCP_PL_PGM == (Xcp_ProtectionStatus & XCP_PL_PGM))
        {
             Xcp_SetErrorCode(XCP_ERR_ACCESS_LOCKED);
             Xcp_RespLength = 0x02u;
        }
        /* check the flash status */
        else if (XCP_IF_BUSY == Xcp_FlsGetStatus())
        {
             Xcp_SetErrorCode(XCP_ERR_PGM_ACTIVE);
             Xcp_RespLength = 0x02u;
        }
        else
        {
            /* set status to XCP_PGM_IDLE because it's the end of program sequence */
            Xcp_PgmStauts = XCP_PGM_IDLE;

            Xcp_DisconnectHal();
            Xcp_RespLength = 0x01u;
            /* call out function to notice whether case device reset*/
            Xcp_ProgramResetNoticeApp();
        }
    }
    Xcp_SendResp();
    return;
}

/* optional */
#if (XCP_GET_PGM_PROCESSOR_INFO == STD_ON)
/******************************************************************************/
/*
 * @brief               <Xcp_Get_Pgm_Processor_Info>
 *
 * < optional command to get program processor info such as support block mode
    or not > .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE) Xcp_GetPgmProcessorInfo(void)
{
#if ((STD_OFF == XCP_CAN_MAX_DLC_REQUIRED) && (STD_ON == XCP_ON_CAN_ENABLE))
    if ((Xcp_CmdLength != 1u)
    && (Xcp_CmdLength != XCP_CAN_MAX_DLC))
    {
        Xcp_SetErrorCode(XCP_ERR_CMD_SYNTAX);
        Xcp_RespLength = 0x02u;
    }
    else
#endif
    {
        /* check the protection status */
        if (XCP_PL_PGM == (Xcp_ProtectionStatus & XCP_PL_PGM))
        {
             Xcp_SetErrorCode(XCP_ERR_ACCESS_LOCKED);
             Xcp_RespLength = 0x02u;
        }
        else
        {
            Xcp_RespBuffer[0u] = 0xFFu;
            Xcp_RespBuffer[1u] = PGM_PROPERTIES;
            Xcp_RespBuffer[2u] = XCP_MAX_SECTOR;
            Xcp_RespLength = 0x03u;
        }
    }
    Xcp_SendResp();
    return;
}
#endif

#if (XCP_GET_SECTOR_INFO == STD_ON)
/******************************************************************************/
/*
 * @brief               <Xcp_Get_Sector_Info>
 *
 * <This optional command is only helpful for the programming method
 *  absolute access mode> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE)  Xcp_GetSectorInfo(void)
{
    uint8 getSectorMode = Xcp_CmdBuffer[1u];
    uint8 getsectorNum = Xcp_CmdBuffer[2u];

    #if ((STD_OFF == XCP_CAN_MAX_DLC_REQUIRED) && (STD_ON == XCP_ON_CAN_ENABLE))
    if ((Xcp_CmdLength != 3u)
    && (Xcp_CmdLength != XCP_CAN_MAX_DLC))
    {
        Xcp_SetErrorCode(XCP_ERR_CMD_SYNTAX);
        Xcp_RespLength = 0x02u;
    }
    else
    #endif
    /* check the protection status */
    if (XCP_PL_PGM == (Xcp_ProtectionStatus & XCP_PL_PGM))
    {
         Xcp_SetErrorCode(XCP_ERR_ACCESS_LOCKED);
         Xcp_RespLength = 0x02u;
    }
    else if (getsectorNum >= XCP_MAX_SECTOR)
    {
       Xcp_SetErrorCode(XCP_ERR_OUT_OF_RANGE);
       Xcp_RespLength = 0x02u;
    }
    else
    {
        switch (getSectorMode)
        {
            /* get start address for this SECTOR mode = 0u */
            case XCP_GER_SECTOR_INFO_MOD_STAD:
            {
                Xcp_RespBuffer[1u] = Xcp_SectorInfo[getsectorNum].sectorclrSequenceNo;
                Xcp_RespBuffer[2u] = Xcp_SectorInfo[getsectorNum].sectorPgmSequenceNo;
                Xcp_RespBuffer[3u] = Xcp_SectorInfo[getsectorNum].sectorPgmMethod;

                /* if mode = 0,get the start address of the sector */
                Xcp_CopyU4ToU1Buffer(Xcp_SectorInfo[getsectorNum].sectorclrStartAddr, &(Xcp_RespBuffer[4u]), CPU_BYTE_ORDER);
                Xcp_RespLength = 0x08u;
                break;
            }
            /* get length of this SECTOR [BYTE] mode = 1u*/
            case XCP_GER_SECTOR_INFO_MOD_LEN:
            {
                Xcp_RespBuffer[1u] = Xcp_SectorInfo[getsectorNum].sectorclrSequenceNo;
                Xcp_RespBuffer[2u] = Xcp_SectorInfo[getsectorNum].sectorPgmSequenceNo;
                Xcp_RespBuffer[3u] = Xcp_SectorInfo[getsectorNum].sectorPgmMethod;

                /* get the length of the sector */
                Xcp_CopyU4ToU1Buffer(Xcp_SectorInfo[getsectorNum].sectorclrLength, &(Xcp_RespBuffer[4u]),CPU_BYTE_ORDER);
                Xcp_RespLength = 0x08u;
                break;
            }
            /* get name length of this SECTOR */
            case XCP_GER_SECTOR_INFO_MOD_NAME:
            {
                /* command automatically sets the Memory Transfer Address (MTA) to
                 * the location from which the Master
                 */
                Xcp_RespBuffer[1u] = Xcp_SectorInfo[getsectorNum].sectorNameLength;

                Xcp_RespLength = 0x02u;

                /* Set the MTA so that the master can upload the ID string. */
                Xcp_MTA.transferAddr = (uint32)(Xcp_SectorInfo[getsectorNum].sectorNamePtr);
                Xcp_MTA.extensionAddr = 0x0u;
                Xcp_UploadInfoLen = (((uint32)Xcp_RespBuffer[1u] - 1u) / XCP_AG) + 1u;
                break;
            }
            default:
            {
                Xcp_SetErrorCode(XCP_ERR_MODE_NOT_VALID);
                Xcp_RespLength = 0x02u;
                break;
            }
        }
    }
    Xcp_SendResp();
    return;
}
#endif

#if (XCP_PROGRAM_PREPARE == STD_ON)
/******************************************************************************/
/*
 * @brief               <Xcp_ProgramPrepare>
 *
 * < xcp program prepare used for xcp bootloader function, not realized yet> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE)  Xcp_ProgramPrepare(void)
{
#if ((STD_OFF == XCP_CAN_MAX_DLC_REQUIRED) && (STD_ON == XCP_ON_CAN_ENABLE))
    if ((Xcp_CmdLength != 6u)
    && (Xcp_CmdLength != XCP_CAN_MAX_DLC))
    {
        Xcp_SetErrorCode(XCP_ERR_CMD_SYNTAX);
        Xcp_RespLength = 0x02u;
    }
    else
#endif
    {
        /* Do Nothing current not supported*/
    }
    Xcp_SendResp();
    return;
}
#endif

#if (XCP_PROGRAM_FORMAT == STD_ON)
/******************************************************************************/
/*
 * @brief               <Xcp_ProgramFormat>
 *
 * <This optional command is used for data encryption and compression and defined
    the program method,access method > .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE)  Xcp_ProgramFormat(void)
{
    /* get the Compression Method from CommandRxObject[1] buffer */
    uint8 pgmCompressionMethod = Xcp_CmdBuffer[1u];
    /* get the Encryption_Method from CommandRxObject[2] buffer */
    uint8 pgmEncryptionMethod = Xcp_CmdBuffer[2u];
    /* get the Programming method from CommandRxObject[3] buffer */
    uint8 pgmProgrammingMethod = Xcp_CmdBuffer[3u];
    /* get the access method from CommandRxObject[4] buffer */
    uint8 pgmAccessMethod = Xcp_CmdBuffer[4u];

    #if ((STD_OFF == XCP_CAN_MAX_DLC_REQUIRED) && (STD_ON == XCP_ON_CAN_ENABLE))
    if ((Xcp_CmdLength != 5u)
    && (Xcp_CmdLength != XCP_CAN_MAX_DLC))
    {
        Xcp_SetErrorCode(XCP_ERR_CMD_SYNTAX);
        Xcp_RespLength = 0x02u;
    }
    else
    #endif
    /* check the protection status */
    if (XCP_PL_PGM == (Xcp_ProtectionStatus & XCP_PL_PGM))
    {
         Xcp_SetErrorCode(XCP_ERR_ACCESS_LOCKED);
         Xcp_RespLength = 0x02u;
    }
    /* Program_format should be used under XCP_PGM_CLEARED status */
    else if (XCP_PGM_CLEARED != Xcp_PgmStauts)
    {
        Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
        Xcp_RespLength = 0x02u;
    }
    /* only support default mode */
    else if ((0u != pgmCompressionMethod)
        || (0u != pgmEncryptionMethod)
        || (0u != pgmProgrammingMethod))
    {
        /* only support default mode */
        Xcp_SetErrorCode(XCP_ERR_RES_TEMP_NOT_A);
        Xcp_RespLength = 0x02u;
    }
    else
    {
        switch (pgmAccessMethod)
        {
            case XCP_ABSOLUTE_ACCESS:
            {
                Xcp_Program_AccessMode = XCP_ABSOLUTE_ACCESS;
                break;
            }
            case XCP_FUNCTIONAL_ACCESS:
            {
                /* Indicate the next progam uses functional mode */
                Xcp_Program_AccessMode = XCP_FUNCTIONAL_ACCESS;
                /* Initialise the block seq counter to 1 */
                Xcp_pgm_blockSeqCounter = 0x01u;
                break;
            }
            default:
            {
                Xcp_SetErrorCode(XCP_ERR_OUT_OF_RANGE);
                Xcp_RespLength = 0x02u;
                break;
            }
        }
    }
    Xcp_SendResp();
    return;
}
#endif

#if (XCP_PROGRAM_NEXT == STD_ON)
/******************************************************************************/
/*
 * @brief               <Xcp_ProgramNext>
 *
  * <This optional command used for block mode to program a block data to flash> .
 * Service ID   :       <SERVICE ID>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE)  Xcp_ProgramNext(void)
{
    Std_ReturnType result = E_OK;
    Xcp_PgmBufferIndexType cnt = 0;
    uint32 programStartAddress = 0u;

    #if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
    uint8 programSeqTmp = 0xffu;
    /* find the min program sequence number in selected sectors */
    for (cnt = 0u ; cnt < XCP_MAX_SECTOR; cnt++)
    {
        if ((TRUE == Xcp_sectorCleared[cnt])
        && (Xcp_SectorInfo[cnt].sectorPgmSequenceNo < programSeqTmp))
        {
            programSeqTmp = Xcp_SectorInfo[cnt].sectorPgmSequenceNo;
        }
    }
    #endif

    /* frame length has been checked before */

    /* check the protection status */
    if (XCP_PL_PGM == (Xcp_ProtectionStatus & XCP_PL_PGM))
    {
        Xcp_SetErrorCode(XCP_ERR_ACCESS_LOCKED);
        Xcp_RespLength = 0x02u;
    }
    /* check the program status */
    else if (XCP_PGM_IDLE == Xcp_PgmStauts)
    {
        Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
        Xcp_RespLength = 0x02u;
    }
    else
    {
        if (XCP_PGM_PROGRAMMING == Xcp_PgmStauts)
        {
            /*get address form MTA[0]*/
            programStartAddress = Xcp_Mta2Ptr(Xcp_MTA.extensionAddr,Xcp_MTA.transferAddr);

            /*if Xcp_flsBufferSize is 0, set Xcp_flsTargetAddr for calibration software(e.g. CANAPE) optimize */
            if (0x00u == Xcp_flsBufferSize)
            {
                Xcp_flsTargetAddr = programStartAddress;
            }
            else if (((Xcp_flsBufferSize + Xcp_flsTargetAddr) != programStartAddress)
            		/*&& (Xcp_BlockBufferLen > XCP_FLS_MIN_WRITE_SIZE))*/
            		&& (Xcp_flsBufferSize > XCP_FLS_MIN_WRITE_SIZE))
            {
                Xcp_flsBufferSize = 0;
                Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
                Xcp_RespLength = 0x02u;
                result = E_NOT_OK;
            }
            else
            {
                /* Do Nothing */
            }
        }
        else
        {
            #if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
            /* do porgram sequence check and get program start address */
            result = Xcp_GetPgmStartAddr_SeqCheck(programSeqTmp,&programStartAddress,Xcp_BlockBufferLen);
            #else
            result = Xcp_GetPgmStartAddr_SeqCheck(&programStartAddress,Xcp_BlockBufferLen);
            #endif
            if (E_OK == result)
            {
                /*if Xcp_flsBufferSize is 0, set Xcp_flsTargetAddr for calibration software(e.g. CANAPE) optimize */
                if (0x00u == Xcp_flsBufferSize)
                {
                    Xcp_flsTargetAddr = programStartAddress;
                }
            }
            else
            {
                Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
                Xcp_RespLength = 0x02u;
            }
        }
        if (E_OK == result)
        {
            /* set the position to 0 */
            Xcp_BlockBufferPos = 0u;
            /* block buffer has enough bytes connect with flsBuffer bytes to achieve min write size */
            if (Xcp_BlockBufferLen >= (XCP_FLS_MIN_WRITE_SIZE - Xcp_flsBufferSize))
            {
                for (cnt = 0u; cnt < (XCP_FLS_MIN_WRITE_SIZE - Xcp_flsBufferSize); cnt++)
                {
                    Xcp_flsBuffer[Xcp_flsBufferSize + cnt] = Xcp_BlockBuffer[cnt];
                }

                Xcp_BlockBufferPos += cnt;
                /* set fls buffer size to min write size */
                Xcp_flsBufferSize = XCP_FLS_MIN_WRITE_SIZE;
                switch (Xcp_Program_AccessMode)
                {
                    case XCP_FUNCTIONAL_ACCESS:
                    {
                        Xcp_pgm_blockSeqCounter ++;
                        break;
                    }
                    case XCP_ABSOLUTE_ACCESS:
                    {
                        Xcp_UpdateMTA((uint32)cnt);
                        break;
                    }
                    default:
                    {
                        /* Do Nothing */
                        break;
                    }
                }
                /* remained data More than min write size, and can do a write action */
                if (E_OK == Xcp_FlsReq(XCP_FLS_WRITE, Xcp_flsTargetAddr, XCP_FLS_MIN_WRITE_SIZE, Xcp_flsBuffer))
                {
                    Xcp_pgmPendingFlag |= XCP_BLOCK_PROGRAM_PENDING;
                }
                else
                {
                    /* set the state to do flash program action */
                    Xcp_pgmPendingFlag |= XCP_BLOCK_PROGRAM_TASK;
                }
            }
            else /**< block buffer hasn't enough bytes*/
            {
                for (cnt = 0u; cnt < Xcp_BlockBufferLen; cnt++)
                {
                    Xcp_flsBuffer[Xcp_flsBufferSize + cnt] = Xcp_BlockBuffer[cnt];
                }
                /* Fls Buffer increase,but not achieve to min write size */
                Xcp_flsBufferSize += cnt;
                switch (Xcp_Program_AccessMode)
                {
                    case XCP_FUNCTIONAL_ACCESS:
                    {
                        Xcp_pgm_blockSeqCounter ++;
                        break;
                    }
                    case XCP_ABSOLUTE_ACCESS:
                    {
                        Xcp_UpdateMTA((uint32)cnt);
                        break;
                    }
                    default:
                    {
                        /* Do Nothing */
                        break;
                    }
                }
            }
        }/* end of E_OK == result */
    }
    if (0x00 == Xcp_pgmPendingFlag)
    {
        Xcp_SendResp();
    }
    return;
}
#endif

#if (XCP_PROGRAM_MAX == STD_ON)
static FUNC(void, XCP_CODE) Xcp_ProgramMaxHal(void)
{
    Std_ReturnType result = E_NOT_OK;
    Xcp_SeqCheckType seqResult = SEQ_OK;
    uint32 programStartAddress = 0u;
	uint8 sectorNum = 0;
    #if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
    uint8 programSeqTmp = 0xffu;
    /* find the min program sequence number in selected sectors */
    for (sectorNum = 0u ; sectorNum < XCP_MAX_SECTOR; sectorNum++)
    {
        if ((TRUE == Xcp_sectorCleared[sectorNum])
        && (Xcp_SectorInfo[sectorNum].sectorPgmSequenceNo < programSeqTmp))
        {
            programSeqTmp = Xcp_SectorInfo[sectorNum].sectorPgmSequenceNo;
        }
    }
    #endif

    if (XCP_PGM_CLEARED == Xcp_PgmStauts)
    {
        /* do porgram sequence check and get program start address */
        #if (XCP_CLEAR_AND_PROGRAM_SEQUENCE_CHECK == STD_ON)
        seqResult= Xcp_GetPgmStartAddr_SeqCheck(programSeqTmp,&programStartAddress,XCP_PROGRAMMAX_SIZE);
        #else
        seqResult= Xcp_GetPgmStartAddr_SeqCheck(&programStartAddress,XCP_PROGRAMMAX_SIZE);
        #endif
        if (SEQ_OK == seqResult)
        {
            Xcp_flsTargetAddr = programStartAddress;
            /*  program size of program_max is fixed */
            result = Xcp_Program_NonZero(programStartAddress,XCP_PROGRAMMAX_SIZE,XCP_PROGRAMMAX_SIZE);
            if (E_OK == result)
            {
                /* set the program status as XCP_PGM_PROGRAMMING */
                Xcp_PgmStauts = XCP_PGM_PROGRAMMING;
            }
            else
            {
                Xcp_SetErrorCode(XCP_ERR_OUT_OF_RANGE);
                Xcp_RespLength = 0x02u;
            }
        }
        else if (SEQ_ERROR == seqResult)/* clear sequence ocuured */
        {
            Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
            Xcp_RespLength = 0x02u;
        }
        else/**< SEQ_OUTRANGE == seqResult */
        {
            Xcp_SetErrorCode(XCP_ERR_ACCESS_DENIED);
            Xcp_RespLength = 0x02u;
        }
    }
    else  if(XCP_PGM_PROGRAMMING == Xcp_PgmStauts)
    {
        switch (Xcp_Program_AccessMode)
        {
            case XCP_ABSOLUTE_ACCESS:
            {
                /*get address form MTA[0]*/
                programStartAddress = Xcp_Mta2Ptr(Xcp_MTA.extensionAddr,Xcp_MTA.transferAddr);
                for (sectorNum = 0u; sectorNum < XCP_MAX_SECTOR; sectorNum++)
                {
                    if ((programStartAddress >= Xcp_SectorInfo[sectorNum].progStartAddr)
                    && (programStartAddress <= (Xcp_SectorInfo[sectorNum].progStartAddr + Xcp_SectorInfo[sectorNum].progDataSize)))
                    {
                        break;
                    }
                }
                if (XCP_MAX_SECTOR == sectorNum)
                {
                    Xcp_flsBufferSize = 0;
                    Xcp_SetErrorCode(XCP_ERR_ACCESS_DENIED);
                    Xcp_RespLength = 0x02u;
                }
                /*if Xcp_flsBufferSize is 0, set Xcp_flsTargetAddr for calibration software(e.g. CANAPE) optimize */
                else if (0x00u == Xcp_flsBufferSize)
                {
                    Xcp_flsTargetAddr = programStartAddress;
                    result = Xcp_Program_NonZero(Xcp_flsTargetAddr,XCP_PROGRAMMAX_SIZE,XCP_PROGRAMMAX_SIZE);
                }
                else if ((Xcp_flsBufferSize + Xcp_flsTargetAddr) != programStartAddress)
                {
                    /* Xcp_flsBufferSize != 0, but the address not continuous,
                     * so clear the size to 0.
                     */
                    Xcp_flsBufferSize = 0;
                    Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
                    Xcp_RespLength = 0x02u;
                }
                else
                {
                    result = Xcp_Program_NonZero(Xcp_flsTargetAddr,XCP_PROGRAMMAX_SIZE,XCP_PROGRAMMAX_SIZE);
                }
                break;
            }
            case XCP_FUNCTIONAL_ACCESS:
            {
                result = Xcp_Program_NonZero(Xcp_flsTargetAddr,XCP_PROGRAMMAX_SIZE,XCP_PROGRAMMAX_SIZE);
                break;
            }
            default:
            {
                result = E_NOT_OK;
                break;
            }
        }
        if (E_NOT_OK == result)
        {
            Xcp_SetErrorCode(XCP_ERR_OUT_OF_RANGE);
            Xcp_RespLength = 0x02u;
        }
    }
    else
    {
    	/* This address is not erased */
    	Xcp_SetErrorCode(XCP_ERR_WRITE_PROTECTED);
    	Xcp_RespLength = 0x02u;
    }
    return;
}
/******************************************************************************/
/*
 * @brief               <Xcp_ProgramMax>
 *
 * <This optional command can not be used in block mode, fixed size(MAX_CTO_PGM-1)
    shall be flashed into  NVM > .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE) Xcp_ProgramMax(void)
{

    /* check frame length */
    #if ((STD_OFF == XCP_CAN_MAX_DLC_REQUIRED) && (STD_ON == XCP_ON_CAN_ENABLE))
    if (Xcp_CmdLength != XCP_CAN_MAX_DLC)
    {
        Xcp_SetErrorCode(XCP_ERR_CMD_SYNTAX);
        Xcp_RespLength = 0x02u;
    }
    else
    #endif
     /* check the protection status */
    if (XCP_PL_PGM == (Xcp_ProtectionStatus & XCP_PL_PGM))
    {
         Xcp_SetErrorCode(XCP_ERR_ACCESS_LOCKED);
         Xcp_RespLength = 0x02u;
    }
     /* check the program status */
    else if ((XCP_PGM_IDLE == Xcp_PgmStauts) || (XCP_PGM_START == Xcp_PgmStauts))
    {
         Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
         Xcp_RespLength = 0x02u;
    }
    else
    {
        Xcp_ProgramMaxHal();
    }
    if (0x00 == Xcp_pgmPendingFlag)
    {
        Xcp_SendResp();
    }
    return;
}
#endif

#if (XCP_PROGRAM_VERIFY == STD_ON)
/******************************************************************************/
/*
 * @brief               <Xcp_ProgramVerify>
 *
 * <This optional command verify the flashed data whether correct or suitable> .
 * Service ID   :       <None>
 * Sync/Async   :       <Synchronous>
 * Reentrancy           <Non Reentrant>
 * @param[in]           <None>
 * @param[out]          <None>
 * @param[in/out]       <None>
 * @return              <None>
 */
/******************************************************************************/
FUNC(void, XCP_CODE) Xcp_ProgramVerify(void)
{
    uint8 verificationMode;
    uint16 verificationType;
    uint32 verificationValue;

    #if ((STD_OFF == XCP_CAN_MAX_DLC_REQUIRED) && (XCP_ON_CAN_ENABLE == STD_ON))
    if (Xcp_CmdLength < 8u)
    {
        Xcp_SetErrorCode(XCP_ERR_CMD_SYNTAX);
        Xcp_RespLength = 0x02u;
    }
    else
    #endif
    {
        /* get the mode from CommandRxObject[1] buffer */
        verificationMode = Xcp_CmdBuffer[1u];

        /* get the verification type from CommandRxObject[2] buffer */
        Xcp_CopyU1BufferToU2(&Xcp_CmdBuffer[2u], &verificationType);

        /* get the verification value from CommandRxObject[4]-[7] buffer */
        Xcp_CopyU1BufferToU4(&Xcp_CmdBuffer[4u], &verificationValue);

        /* check the program status */
        if (XCP_PGM_PROGRAMMED != Xcp_PgmStauts)
        {
             Xcp_SetErrorCode(XCP_ERR_SEQUENCE);
             Xcp_RespLength = 0x02u;
        }
        /* if request to start internal routine*/
        else if (0u == verificationMode)
        {
            Xcp_SetErrorCode(XCP_ERR_RES_TEMP_NOT_A);
            Xcp_RespLength = 0x02u;
        }
        else
        {
            /* verification_type and verification_value check */
        }
    }
    Xcp_SendResp();
    return;
}
#endif
#define XCP_STOP_SEC_CODE
#include "XCP_MemMap.h"

#endif /* (XCP_PL_PGM == (XCP_PL_PGM&XCP_RESOURCE)) */

/*=======[E N D   O F   F I L E]==============================================*/

